Skip to content

Fix #6909: Cache alias givens in lazy vals #7006

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Aug 12, 2019

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Aug 7, 2019

No description provided.

Copy link
Member

@dottybot dottybot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello, and thank you for opening this PR! 🎉

All contributors have signed the CLA, thank you! ❤️

Commit Messages

We want to keep history, but for that to actually be useful we have
some rules on how to format our commit messages (relevant xkcd).

Please stick to these guidelines for commit messages:

  1. Separate subject from body with a blank line
  2. When fixing an issue, start your commit message with Fix #<ISSUE-NBR>:
  3. Limit the subject line to 72 characters
  4. Capitalize the subject line
  5. Do not end the subject line with a period
  6. Use the imperative mood in the subject line ("Add" instead of "Added")
  7. Wrap the body at 80 characters
  8. Use the body to explain what and why vs. how

adapted from https://chris.beams.io/posts/git-commit

Have an awesome day! ☀️

@odersky
Copy link
Contributor Author

odersky commented Aug 7, 2019

@nicolasstucki Can you take a look at this? I get:

-- Error: i3912_2.scala:5:21 ---------------------------------------------------
5 |  val a3: Unit = foo3()
  |                 ^^^^^^
  |Exception occurred while executing macro expansion.
  |java.lang.NoSuchMethodError: scala.quoted.Liftable$.Liftable_Int_delegate()Lscala/quoted/Liftable;
  |	at Macros$.impl(i3912_1.scala:10)
  |
  | This location is in code that was inlined at i3912_2.scala:5
one error found

But I get the same problem when I run this locally at master. So I am not sure what's to blame for it; maybe nothing in the PR itself.

@nicolasstucki
Copy link
Contributor

If you switch to master you probably need to clean out/bootstrap/dotty-library-bootstrapped. To make it work again.

That call to Liftable_Int_delegate is generated here. The definition of that delegate is here.

I noticed that the signature in the bytecode changed from

public final PrimitiveLiftable<Object> Liftable_Int_delegate()

to

public final Liftable<Object> Liftable_Int_delegate()

This might be the source of the problem.

@odersky
Copy link
Contributor Author

odersky commented Aug 7, 2019

I noticed that the signature in the bytecode changed from

public final PrimitiveLiftable<Object> Liftable_Int_delegate()

to

public final Liftable<Object> Liftable_Int_delegate()

This might be the source of the problem.

Yes, that looks likely. The new type, Liftable, is the correct one. If the result type should be PrimitiveLiftable the given instance has to be declared as one.

@nicolasstucki
Copy link
Contributor

Sorry, I inverted the snippets. Master has Liftable<Object> and this branch has PrimitiveLiftable<Object>.

@nicolasstucki
Copy link
Contributor

nicolasstucki commented Aug 7, 2019

Yes, now the signature is wrong.

I forced it to have Liftable and it worked.

given Liftable_Int_delegate as Liftable[Int] = primitiveLiftable

private def primitiveLiftable[T <: Unit | Null | Int | Boolean | Byte | Short | Int | Long | Float | Double | Char | String]: Liftable[T] = new PrimitiveLiftable

private class PrimitiveLiftable[T <: Unit | Null | Int | Boolean | Byte | Short | Int | Long | Float | Double | Char | String] extends Liftable[T] {
  ....
}

@odersky odersky changed the title Fix #6009: Cache alias givens in lazy vals Fix #6909: Cache alias givens in lazy vals Aug 7, 2019
@odersky
Copy link
Contributor Author

odersky commented Aug 7, 2019

OK, I am out of my wits here. dotty-library-bootstrappedJS fails with this error:

error] Illegal tree in gen of genInterface(): ValDef(OFFSET$_m_0,TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Long)],Apply(Select(Ident(LazyVals),getOffset),List(Literal(Constant(ClassInfo(NoPrefix, module class Liftable$, List(TypeRef(ThisType(TypeRef(NoPrefix,module class lang)),class Object), TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Serializable))))), Literal(Constant(bitmap$0)))))
--
18376 | [error] (dotty-library-bootstrappedJS / Compile / compileIncremental) Compilation failed

It seems that it tries to generate a lazy val offset variable in an interface. The lazy val is probably generated from the given cache. But the generated lazy val seems to be exactly the same as a user-written one. Who can help and find out what the problem is? Maybe someone has a better idea what this could be. Or we need to start triaging to figure out exactly what file fails. It would be good to finally fix #6909 which has already tripped up several people.

@odersky odersky removed their assignment Aug 7, 2019
@odersky
Copy link
Contributor Author

odersky commented Aug 11, 2019

Here's a more informative error message:

Illegal tree in gen of genInterface(): @scala.annotation.static() @scala.annotation.static() val OFFSET$_m_0: Long =
--
18388 | [error] dotty.runtime.LazyVals.getOffset(classOf[Object with Serializable {...}],
18389 | [error] "bitmap$0"
18390 | [error] )
18391 | [error] class = @scala.annotation.internal.SourceFile(
18392 | [error] "/tmp/2/library/src-bootstrapped/scala/quoted/Liftable.scala"
18393 | [error] ) trait Liftable() extends Object {
18394 | [error] @scala.annotation.static() private def <clinit>(): Unit =
18395 | [error] {
18396 | [error] Liftable.this.OFFSET$_m_0 =
18397 | [error] dotty.runtime.LazyVals.getOffset(classOf[Object with Serializable {...}]
18398 | [error] ,
18399 | [error] "bitmap$0")
18400 | [error] ()
18401 | [error] }
18402 | [error] def toExpr(x: Object): Function1
18403 | [error] def toExpr$direct(x: Object, x$0: scala.quoted.QuoteContext):
18404 | [error] scala.quoted.Expr
18405 | [error] @scala.annotation.static() @scala.annotation.static() val OFFSET$_m_0: Long =
18406 | [error] dotty.runtime.LazyVals.getOffset(classOf[Object with Serializable {...}],
18407 | [error] "bitmap$0"
18408 | [error] )
18409 | [error] }
18410 | [error] in /tmp/2/library/src-bootstrapped/scala/quoted/Liftable.scala
18411 | [error] (dotty-library-bootstrappedJS / Compile / compileIncremental) Compilation failed

The OFFSET field has the static annotation (twice!, no idea why) so it should be legal in an interface.

@sjrd Can you suggest how to fix this?

We have an annoying problem here:

In fact, it's likely that a revised LazyVals would also need to generate static ValDefs in traits, so the problem should be fixed on the Js generation side.

@sjrd
Copy link
Member

sjrd commented Aug 12, 2019

I will see what I can do today. I believe the easiest is actually to change the lazy val transform so that it generates something simpler for JS. The current scheme and the new proposed scheme are both unsuitable for JS, because they use Unsafe, and are completely overkill for a single-threaded environment anyway.

@odersky
Copy link
Contributor Author

odersky commented Aug 12, 2019

I will see what I can do today. I believe the easiest is actually to change the lazy val transform so that it generates something simpler for JS. The current scheme and the new proposed scheme are both unsuitable for JS, because they use Unsafe, and are completely overkill for a single-threaded environment anyway.

Indeed. Maybe it's simplest to always assume @ThreadUnsafe for lazy vals under JS?

Stale symbol errors can happen when inspecting symbols while comparing
the trees before and after pickling.
Restricting `entered` and `enteredAfter` to class members is more a trap to
fall into than a helpful check.
The new implementation does not optimize given aliases with pure paths as right hand sides to be
vals anymore. The reason is that even a pure path might be expensive to compute so we might want
the caching. If we want a precomputed val, we can always for this with an explicit value definition:
```
val x = a.b.c
given as T = x
```
It's not necessary anyway, and changes the meaning of `inline`.
The current LazyVals implementation contains initialization code for the OFFSET value.
Therefore we cannot set a NoInits flag for traits containing alias givens since these
might become lay vals.

If the lazy val implementation changes we might be able to revert that commit.
@liufengyun liufengyun self-requested a review August 12, 2019 15:25
@liufengyun liufengyun self-assigned this Aug 12, 2019
Copy link
Contributor

@liufengyun liufengyun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@liufengyun liufengyun merged commit 0ebbcff into scala:master Aug 12, 2019
@liufengyun liufengyun deleted the fix-#6009 branch August 12, 2019 15:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants